

/*
1. 实现一个 packet mempool , 支持固定长度 512 Bytes 长度的 packet.
	支持 drv 端发来 malloc 和 free 请求.
	也支持 app 端发来的 malloc 和 free 请求.
	目前考虑 app 端通过 ecall 来进入服务处理流程, 并且保持关闭中断状态.
	
2. 实现 2 个单项消息通道.
    drv >>>>  app :  host 发送到 OUT endp,  驱动处理后进入消息通道, 等待 app 主动来查询接收.
    drv <<<<  app :  
*/

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>

#include "ufifo.h"


ufifo_t * p_upk_pool = NULL;
ufifo_t * p_upk_dev2app = NULL;
ufifo_t * p_upk_app2dev = NULL;



int upk_init( void )
{
	int iret;
	uint16_t temp;
	uint8_t * ptr;

	iret = ufifo_alloc( 8, &p_upk_pool );
	if ( iret != 0 )  {
		return 100 + iret;
	}

	iret = ufifo_alloc( 8, &p_upk_dev2app );
	if ( iret != 0 )  {
		return 200 + iret;
	}	

	iret = ufifo_alloc( 8, &p_upk_app2dev );
	if ( iret != 0 )  {
		return 300 + iret;
	}

	// 不需要填满 upk_pool ,
	ptr = (uint8_t *)malloc( 252 * 512 );

	//  align to 512.
	temp = (uint16_t)(intptr_t)ptr;
	if ( (temp & 0x1FF) != 0 )  {
		temp = 512 - (temp & 0x1FF);
		ptr += temp;
	}
	
	for ( int i=0; i<250; i++ )  {
		ufifo_enqueue( p_upk_pool, (uint64_t)(intptr_t)ptr );
		ptr += 512;
	}

	/**/
	return 0;
}


void * upk_alloc( void )
{
	int iret;
	uint64_t temp;
	void * ptr = NULL;
	
	/**/
	iret = ufifo_dequeue( p_upk_pool, &temp );
	if ( iret != 0 )  {
		return NULL;
	}

	/**/
	ptr = (void *)(intptr_t)temp;
	return ptr;
}


void upk_free( void * ptr )
{
	ufifo_enqueue( p_upk_pool, (uint64_t)(intptr_t)ptr );
	return;
}


/*
输出
	ptr,
	length

return:
	iret = 0 表示成功, 其他错误.
*/

int upk_recv_from_app( void ** pptr, int * plen )
{
	int iret;
	uint64_t temp;

	/**/
	iret = ufifo_dequeue( p_upk_app2dev, &temp );
	if ( iret != 0 )  {
		return 100 + iret;
	}

	/**/
	*plen = (int)(uint32_t)temp;
	*pptr = (void *)(intptr_t)(temp >> 32);
	return 0;
}


int upk_send_to_app( void * ptr, int tlen )
{
	uint64_t temp;

	/**/
	temp = (uint64_t)(intptr_t)ptr;
	temp = (temp << 32 ) | tlen;

	/**/
	ufifo_enqueue( p_upk_dev2app, temp );
	return 0;
}



int upk_recv_from_dev( void ** pptr, int * plen )
{
	int iret;
	uint64_t temp;

	/**/
	iret = ufifo_dequeue( p_upk_dev2app, &temp );
	if ( iret != 0 )  {
		printf( "deque fail, %d\n", iret );
		return 200 + iret;
	}
	
	/**/
	*plen = (int)(uint32_t)temp;
	*pptr = (void *)(intptr_t)(temp >> 32);
	return 0;
}


int upk_send_to_dev( void * ptr, int tlen )
{
	uint64_t temp;

	/**/
	temp = (uint64_t)(intptr_t)ptr;
	temp = (temp << 32 ) | tlen;

	/**/
	ufifo_enqueue( p_upk_app2dev, temp );
	return 0;
}

